<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="noodp" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
        <title>《Dart之笨办法学Dart Dartdoc - 飞雪无情的博客</title><meta name="Description" content="专注于IT互联网，包括但不限于Go语言(golang)、Java、Android、Python、项目管理、抖音分析、软件架构等"><meta property="og:title" content="《Dart之笨办法学Dart Dartdoc" />
<meta property="og:description" content="
Flutter SDK 的 dartdoc.dart 脚本不仅可以演示了 dartdoc 各参数的用法，它也是学习 Dart 编程语言的绝好参考资料。
" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://www.flysnow.org/posts/flutter/Dart%E4%B9%8B%E7%AC%A8%E5%8A%9E%E6%B3%95%E5%AD%A6Dart-dartdoc.dart%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/" />
<meta property="article:published_time" content="2021-07-31T21:00:31+08:00" />
<meta property="article:modified_time" content="2021-07-31T21:00:31+08:00" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="《Dart之笨办法学Dart Dartdoc"/>
<meta name="twitter:description" content="
Flutter SDK 的 dartdoc.dart 脚本不仅可以演示了 dartdoc 各参数的用法，它也是学习 Dart 编程语言的绝好参考资料。
"/>
<meta name="application-name" content="飞雪无情的博客">
<meta name="apple-mobile-web-app-title" content="飞雪无情的博客"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="manifest" href="/site.webmanifest"><link rel="canonical" href="https://www.flysnow.org/posts/flutter/Dart%E4%B9%8B%E7%AC%A8%E5%8A%9E%E6%B3%95%E5%AD%A6Dart-dartdoc.dart%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/" /><link rel="prev" href="https://www.flysnow.org/posts/flutter/Dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8BIsolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" /><link rel="next" href="https://www.flysnow.org/posts/flutter/Flutter%E4%B9%8BRenderObject%E4%BB%8B%E7%BB%8D/" /><link rel="stylesheet" href="/lib/normalize/normalize.min.css"><link rel="stylesheet" href="/css/style.min.css"><link rel="stylesheet" href="/lib/fontawesome-free/all.min.css"><link rel="stylesheet" href="/lib/animate/animate.min.css"><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "《Dart之笨办法学Dart Dartdoc",
        "inLanguage": "zh-CN",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https:\/\/www.flysnow.org\/posts\/flutter\/Dart%E4%B9%8B%E7%AC%A8%E5%8A%9E%E6%B3%95%E5%AD%A6Dart-dartdoc.dart%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90\/"
        },"genre": "posts","keywords": "dart","wordcount":  1724 ,
        "url": "https:\/\/www.flysnow.org\/posts\/flutter\/Dart%E4%B9%8B%E7%AC%A8%E5%8A%9E%E6%B3%95%E5%AD%A6Dart-dartdoc.dart%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90\/","datePublished": "2021-07-31T21:00:31+08:00","dateModified": "2021-07-31T21:00:31+08:00","publisher": {
            "@type": "Organization",
            "name": "飞雪无情"},"author": {
                "@type": "Person",
                "name": "飞雪无情"
            },"description": ""
    }
    </script></head>
    <body header-desktop="" header-mobile=""><script type="text/javascript">(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : '' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>

        <div id="mask"></div><div class="wrapper"><div class="logo-wrapper">
  <a href="/%20/" class="logo">飞雪无情的博客</a>
</div>

<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
      <a class="menu-item-link" href="/tools/">工具</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/archives/">归档</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/about/">关于</a>
    </li>
  </ul>
</nav><main class="main">
                <div class="container"><div class="toc" id="toc-auto">
            <h2 class="toc-title">Contents</h2>
            <div class="toc-content" id="toc-content-auto"></div>
        </div><article class="page single"><h1 class="single-title animated flipInX">《Dart之笨办法学Dart Dartdoc</h1><div class="post-meta">
            <div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel=" author" class="author"><i class="fas fa-user-circle fa-fw"></i>飞雪无情</a></span>&nbsp;<span class="post-category">included in <a href="/categories/dart/"><i class="far fa-folder fa-fw"></i>dart</a></span></div>
            <div class="post-meta-line"><i class="far fa-calendar-alt fa-fw"></i>&nbsp;<time datetime="2021-07-31">2021-07-31</time>&nbsp;<i class="fas fa-pencil-alt fa-fw"></i>&nbsp;1724 words&nbsp;
                <i class="far fa-clock fa-fw"></i>&nbsp;4 minutes&nbsp;</div>
        </div><div class="featured-image"><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png, https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png"
        title="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png" /></div><div class="details toc" id="toc-static"  kept="">
                <div class="details-summary toc-title">
                    <span>Contents</span>
                    <span><i class="details-icon fas fa-angle-right"></i></span>
                </div>
                <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#args-库">args 库</a></li>
    <li><a href="#path-库">path 库</a></li>
    <li><a href="#process-库">process 库</a></li>
    <li><a href="#文件操作">文件操作</a></li>
    <li><a href="#正则式">正则式</a></li>
    <li><a href="#其他">其他</a></li>
  </ul>

  <ul>
    <li><a href="#使用">使用</a></li>
    <li><a href="#参数">参数</a></li>
    <li><a href="#dartdoc_optionsyaml">dartdoc_options.yaml</a></li>
    <li><a href="#简单例子">简单例子</a></li>
  </ul>
</nav></div>
            </div><div class="content" id="content"><blockquote>
<p>Flutter SDK 的 <a href="https://github.com/flutter/flutter/blob/master/dev/tools/dartdoc.dart" target="_blank" rel="noopener noreffer">dartdoc.dart</a> 脚本不仅可以演示了 <code>dartdoc</code> 各参数的用法，它也是学习 Dart 编程语言的绝好参考资料。</p>
</blockquote>
<p>Dart SDK 中的 <code>dartdoc</code> 命令用于从 Dart 源码生成文档。使用过程中遇到问题，一番搜索后发现 Flutter SDK 的 <code>dartdoc.dart</code> 脚本是对该命令的封装。这个脚本用于生成 Flutter 文档。我发现从 <code>dartdoc.dart</code> 中不仅能学习到 <code>dartdoc</code> 各参数的用法，它还是学习 Dart 编程语言的绝好参考资料。学习并记录一下。(看似挺笨的学习方法，但感觉有效)</p>
<p>一方面是 Dart 语言相关的知识：</p>
<ul>
<li>第三方简单用法
<ul>
<li>argParser</li>
<li>path</li>
<li>process</li>
</ul>
</li>
<li>文件操作
<ul>
<li>文件生成和读写</li>
<li>切换及遍历目录</li>
</ul>
</li>
<li>进程操作</li>
<li>Dart 语言特性
<ul>
<li>Synchronous generator</li>
<li>扩展操作符</li>
<li>字符串操作</li>
</ul>
</li>
<li>正则表达式</li>
</ul>
<p>另一方面是 Dart dartdoc 的用法。</p>
<p>dartdoc.dart 脚本见 <a href="https://github.com/flutter/flutter/blob/master/dev/tools/dartdoc.dart" target="_blank" rel="noopener noreffer">Github</a>。另外注意区分 dartdoc.dart 和 Dart <code>dartdoc</code>，前者是 Flutter SDK 中用于生成文档的脚本，是对后者的封装；后者则是 Dart SDK 的内置命令。</p>
<h1 id="dart-语言">Dart 语言</h1>
<p><code>dartdoc.dart</code> 函数了以下内容。</p>
<h2 id="args-库">args 库</h2>
<p>首先要引入 <a href="https://pub.dev/packages/args" target="_blank" rel="noopener noreffer">args库</a>，在 <code>pubspec.yaml</code> 中添加如下依赖：</p>
<pre><code>dependencies:
  args: 1.5.2
</code></pre><p>arg 库的基本用法包括：</p>
<ul>
<li>
<p>创建 ArgParser - <code>ArgParser()</code></p>
</li>
<li>
<p>添加 flag - <code>ArgParser.addFlag()</code></p>
</li>
<li>
<p>生成 ArgResults - <code>ArgParser.parse()</code></p>
</li>
<li>
<p>访问</p>
<pre><code>ArgResults
</code></pre><ul>
<li>显示当前程序的用法 - <code>ArgResults.usage</code></li>
<li>访问传给当前程序的参数 - <code>[]</code></li>
</ul>
</li>
</ul>
<p>示例代码如下：</p>
<pre><code>ArgParser _createArgsParser() {
  // 1 - 创建 ArgParser
  final ArgParser parser = ArgParser();
  parser.addFlag('help', abbr: 'h', negatable: false,
      help: 'Show command help.');
  // 2 - 添加 flag
  parser.addFlag('verbose', negatable: true, defaultsTo: true,
      help: 'Whether to report all error messages (on) or attempt to '
          'filter out some known false positives (off).  Shut this off '
          'locally if you want to address Flutter-specific issues.');
  ...
  return parser;
}

Future&lt;void&gt; main(List&lt;String&gt; arguments) async {
  final ArgParser argParser = _createArgsParser();
  // 3 - 生成 ArgResults
  final ArgResults args = argParser.parse(arguments);
  if (args['help']) {
    print ('Usage:');
    // 4 - 访问 `ArgResults`
    print (argParser.usage);
    exit(0);
  }
}
</code></pre><p>Flag 支持的选项包括：</p>
<ul>
<li><code>negatable</code> - 是否可忽略</li>
<li><code>abbr</code> - 缩写命令，比如 <code>--help</code> 的短命令是 <code>-h</code></li>
<li><code>defaultsTo</code> - 缺省值</li>
</ul>
<h2 id="path-库">path 库</h2>
<p>首先要引入 <a href="https://pub.dev/packages/path" target="_blank" rel="noopener noreffer">path库</a>，在 <code>pubspec.yaml</code> 中添加如下依赖：</p>
<pre><code>dependencies:
  path: 1.6.4
</code></pre><p>Dart 中使用 <code>Directory</code> 类可获取当前目录，通过 path 库可获取到目录名和文件名。示例代码如下：</p>
<pre><code>// 获取当前目录
Directory.current.path; // -&gt; /Users/cm/wd/flutter_web/lib/learn_dartdoc

// 切换目录
if (path.basename(Directory.current.path) == 'tools') {
  Directory.current = Directory.current.parent.parent;
}

// 获取当前目录名
path.basename('path/to/foo.dart'); // -&gt; 'foo.dart'
path.basename('path/to');          // -&gt; 'to'
path.basename('path/to/'); // -&gt; 'to'
</code></pre><h2 id="process-库">process 库</h2>
<p><code>dartdoc.dart</code> 脚本中有这样一段代码：</p>
<pre><code>final ProcessResult flutter = Process.runSync('flutter', &lt;String&gt;[]);
final File versionFile = File('version');
if (flutter.exitCode != 0 || !versionFile.existsSync())
  throw Exception('Failed to determine Flutter version.');
</code></pre><p>这段代码的功能包括：</p>
<ul>
<li>使用 <code>Process.runSync()</code> 启动 <code>flutter</code> 命令并检查是否运行成功</li>
<li>使用 <code>File.existsSync()</code> 检查 <code>&lt;FLUTTER DIR&gt;/version</code> 文件是否存在</li>
</ul>
<p>引入 <a href="https://pub.dev/packages/process" target="_blank" rel="noopener noreffer">path库</a>，在 <code>pubspec.yaml</code> 中添加如下依赖：</p>
<pre><code>dependencies:
  process: 3.0.12
</code></pre><p><a href="https://pub.dev/packages/process" target="_blank" rel="noopener noreffer">process 库</a> 的 <code>ProcessWrapper</code> 是对 Dart <code>Process</code> 的包装，以提供更方便的方法。其用法如下：</p>
<pre><code>// Run pub.
ProcessWrapper process = ProcessWrapper(await Process.start(
  pubExecutable,
  &lt;String&gt;['get'],
  workingDirectory: kDocsRoot,
  environment: pubEnvironment,
));
printStream(process.stdout, prefix: 'pub:stdout: ');
printStream(process.stderr, prefix: 'pub:stderr: ');
final int code = await process.done;
</code></pre><h2 id="文件操作">文件操作</h2>
<p><code>dartdoc.dart</code> 脚本中用到几种基本的文件操作，</p>
<ul>
<li>写文件</li>
<li>读文件</li>
<li>创建目录</li>
<li>遍历目录</li>
</ul>
<p><code>File.writeAsStringSync(String)</code> 方法用于将字符串写入文件。用法如下：</p>
<pre><code>// Create the pubspec.yaml file.
final StringBuffer buf = StringBuffer();
buf.writeln('name: Flutter');
buf.writeln('homepage: https://flutter.dev');
...
File('$kDocsRoot/pubspec.yaml').writeAsStringSync(buf.toString());
</code></pre><p><code>Directory.createSync()</code> 方法用于创建目录。用法如下：</p>
<pre><code>// Create the library file.
final Directory libDir = Directory('$kDocsRoot/lib');
libDir.createSync();
</code></pre><p><code>dartdoc.dart</code> 包含的一个功能是遍历 Flutter SDK <code>packages</code> 目录来找到所有的库路径：</p>
<pre><code>/// Returns import or on-disk paths for all libraries in the Flutter SDK.
Iterable&lt;String&gt; libraryRefs() sync* {
  for (Directory dir in findPackages()) {
    final String dirName = path.basename(dir.path);
    for (FileSystemEntity file in Directory('${dir.path}/lib').listSync()) {
      if (file is File &amp;&amp; file.path.endsWith('.dart')) {
        yield '$dirName/${path.basename(file.path)}';
      }
    }
  }

  // Add a fake package for platform integration APIs.
  yield 'platform_integration/android.dart';
  yield 'platform_integration/ios.dart';
}

/// Finds all packages in the Flutter SDK
List&lt;FileSystemEntity&gt; findPackages() {
  return Directory('&lt;FLUTTER SDK&gt;/packages')
    .listSync()
    .where((FileSystemEntity entity) {
      return false;
    })
    .cast&lt;Directory&gt;()
    .toList();
}
</code></pre><p>从这段代码可以学到两个知识点：</p>
<ul>
<li>首先，注意 <code>libraryRefs()</code> 方法中用到的 <code>sync*</code> 和 <code>yield</code> 的用法。实际上这里返回的 <code>Iterable</code> 是 <a href="https://dart.dev/guides/language/language-tour#generators" target="_blank" rel="noopener noreffer">synchronous generator</a></li>
<li>其次，<code>Directory.listSync()</code> 返回当前目录中的所有文件和目录。该方法的参数 <code>recursive</code> 用于支持递归遍历</li>
</ul>
<h2 id="正则式">正则式</h2>
<p><code>dartdoc.dart</code> 中用到了正则式。限于篇幅，这里不展开。</p>
<pre><code>printStream(process.stdout, prefix: args['json'] ? '' : 'dartdoc:stdout: ',
  filter: args['verbose'] ? const &lt;Pattern&gt;[] : &lt;Pattern&gt;[
    RegExp(r'^generating docs for library '), // unnecessary verbosity
    RegExp(r'^pars'), // unnecessary verbosity
  ],
);
printStream(process.stderr, prefix: args['json'] ? '' : 'dartdoc:stderr: ',
  filter: args['verbose'] ? const &lt;Pattern&gt;[] : &lt;Pattern&gt;[
    RegExp(r'^ warning: .+: \(.+/\.pub-cache/hosted/pub.dartlang.org/.+\)'), // packages outside our control
  ],
);
</code></pre><h2 id="其他">其他</h2>
<p>这里来看一些小的语言特性。小则小，用起来确实方便。</p>
<p>一，可以将 <code>if</code> 表达式用于 List 字面量的创建。</p>
<pre><code>final List&lt;String&gt; dartdocBaseArgs = &lt;String&gt;[
  'global',
  'run',
  if (args['checked']) '-c',
  'dartdoc',
];
</code></pre><p>二，Dart 提供 <code>...</code> 扩展操作符。用法如下：</p>
<pre><code>final List&lt;String&gt; dartdocBaseArgs = &lt;String&gt;[
  'global',
  'run',
  if (args['checked']) '-c',
  'dartdoc',
];

// Verify which version of dartdoc we're using.
final ProcessResult result = Process.runSync(
  pubExecutable,
  &lt;String&gt;[...dartdocBaseArgs, '--version'],
  workingDirectory: kDocsRoot,
  environment: pubEnvironment,
);
</code></pre><h1 id="dart-dartdoc-命令httpsgithubcomdart-langdartdocdartdoc"><a href="https://github.com/dart-lang/dartdoc#dartdoc" target="_blank" rel="noopener noreffer">Dart dartdoc 命令</a></h1>
<blockquote>
<p>Use dartdoc to generate HTML documentaton for your Dart package.</p>
</blockquote>
<p>Dart dartdoc 是 Dart SDK 中用于为 Dart package 生成 HTML 文档的命令行工具。</p>
<p>要正确使用这个工具，建议先简单了解以下内容：</p>
<ul>
<li><a href="https://dart.dev/guides/libraries/create-library-packages" target="_blank" rel="noopener noreffer">Dart package 的组织方式</a></li>
<li><a href="https://dart.dev/guides/language/effective-dart/documentation#doc-comments" target="_blank" rel="noopener noreffer">Dart 注释文档最佳实践</a></li>
</ul>
<p>最简单的 Dart package 目录结构如下：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://www.sunmoonblog.com/images/15749233895070.jpg"
        data-srcset="https://www.sunmoonblog.com/images/15749233895070.jpg, https://www.sunmoonblog.com/images/15749233895070.jpg 1.5x, https://www.sunmoonblog.com/images/15749233895070.jpg 2x"
        data-sizes="auto"
        alt="https://www.sunmoonblog.com/images/15749233895070.jpg"
        title="img" /></p>
<ul>
<li>pubspec file</li>
<li>lib directory
<ul>
<li>lib 目录下可以创建任意目录结构</li>
<li>lib/src 目录下的代码是私有的，通常是具体实现</li>
<li>lib 目录下的代码是公开的</li>
<li>可以通过 lib 目录下的文件导出 lib/src 为公开代码</li>
</ul>
</li>
</ul>
<p>更完整的代码结构可以参考 <a href="https://github.com/dart-lang/shelf" target="_blank" rel="noopener noreffer">shelf</a>。</p>
<h2 id="使用">使用</h2>
<p>Dart SDK 自带 dartdoc，不用另外安装。</p>
<ul>
<li>生成文档 - 在根目录下运行 <code>dartdoc</code></li>
<li>查看文档
<ul>
<li><code>dhttpd --path doc/api</code> 启动服务</li>
<li><code>http://localhost:8080</code> 查看</li>
</ul>
</li>
</ul>
<h2 id="参数">参数</h2>
<p>Dart dartdoc 命令支持相当多的参数。以 Flutter 为例，生成文档时的参数如下：</p>
<pre><code>dartdoc
    --allow-tools
    --no-validate-links
    --link-to-source-excludes ../../bin/cache
    --link-to-source-root ../.. 
    --link-to-source-uri-template https://github.com/flutter/flutter/blob/master/%f%#L%l%
    --inject-html
    --header styles.html
    --header analytics.html 
    --header survey.html
    --header snippets.html
    --header opensearch.html
    --footer-text lib/footer.html
    --allow-warnings-in-packages Flutter,flutter,platform_integration,flutter_test,...
    --exclude package:Flutter/temp_doc.dart,package:http/browser_client.dart,...
    --favicon=favicon.ico
    --package-order flutter,Dart,...
    --auto-include-dependencies)
</code></pre><p>实际使用时可以参考 <a href="https://github.com/dart-lang/dartdoc#dartdoc" target="_blank" rel="noopener noreffer">dart-lang/dartdoc: API documentation tool for Dart.</a>。</p>
<h2 id="dartdoc_optionsyaml">dartdoc_options.yaml</h2>
<p>可以通过在根目录下创建 <code>dartdoc_options.yaml</code> 来控制调整生成的文档。</p>
<pre><code>dartdoc:
  exclude: []
</code></pre><p>详细参数见 <a href="https://github.com/dart-lang/dartdoc#advanced-features" target="_blank" rel="noopener noreffer">Github</a></p>
<h2 id="简单例子">简单例子</h2>
<p>这里用一个简单的例子演示 dartdoc 的用法。代码结构和 <code>dartdoc_options.yaml</code> 分别如下：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://www.sunmoonblog.com/images/15749244487548.jpg"
        data-srcset="https://www.sunmoonblog.com/images/15749244487548.jpg, https://www.sunmoonblog.com/images/15749244487548.jpg 1.5x, https://www.sunmoonblog.com/images/15749244487548.jpg 2x"
        data-sizes="auto"
        alt="https://www.sunmoonblog.com/images/15749244487548.jpg"
        title="-w885" /></p>
<p>我们在 <code>exclude</code> 中排除了 <code>hello.dart</code> 和 <code>bar.dart</code> 两个文件，而 <code>lib/src</code> 下的代码为私有的，所以最终仅为 <code>hello2.dart</code> 生成了文档。</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://www.sunmoonblog.com/images/15749246280161.jpg"
        data-srcset="https://www.sunmoonblog.com/images/15749246280161.jpg, https://www.sunmoonblog.com/images/15749246280161.jpg 1.5x, https://www.sunmoonblog.com/images/15749246280161.jpg 2x"
        data-sizes="auto"
        alt="https://www.sunmoonblog.com/images/15749246280161.jpg"
        title="-w773" /></p>
<p>浏览器中看到了文档是这样的：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://www.sunmoonblog.com/images/15749249251449.jpg"
        data-srcset="https://www.sunmoonblog.com/images/15749249251449.jpg, https://www.sunmoonblog.com/images/15749249251449.jpg 1.5x, https://www.sunmoonblog.com/images/15749249251449.jpg 2x"
        data-sizes="auto"
        alt="https://www.sunmoonblog.com/images/15749249251449.jpg"
        title="-w723" /></p></div><div class="post-footer" id="post-footer">
    <div class="post-info">
        <div class="post-info-line">
            <div class="post-info-mod">
                <span>Updated on 2021-07-31</span>
            </div>
            <div class="post-info-license"></div>
        </div>
        <div class="post-info-line">
            <div class="post-info-md"></div>
            <div class="post-info-share">
                <span></span>
            </div>
        </div>
    </div>

    <div class="post-info-more">
        <section class="post-tags"><i class="fas fa-tags fa-fw"></i>&nbsp;<a href="/tags/dart/">dart</a></section>
        <section>
            <span><a href="javascript:void(0);" onclick="window.history.back();">Back</a></span>&nbsp;|&nbsp;<span><a href="/">Home</a></span>
        </section>
    </div>

    <div class="post-nav"><a href="/posts/flutter/Dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8BIsolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" class="prev" rel="prev" title="《Dart异步编程之Isolate和事件循环》"><i class="fas fa-angle-left fa-fw"></i>《Dart异步编程之Isolate和事件循环》</a>
            <a href="/posts/flutter/Flutter%E4%B9%8BRenderObject%E4%BB%8B%E7%BB%8D/" class="next" rel="next" title="《Flutter之RenderObject介绍》">《Flutter之RenderObject介绍》<i class="fas fa-angle-right fa-fw"></i></a></div>
</div>
</article></div>
            </main><footer class="footer">
        <div class="footer-container"><div class="footer-line">Powered by <a href="https://gohugo.io/" target="_blank" rel="noopener noreffer" title="Hugo 0.79.1">Hugo</a> | Theme - <a href="https://github.com/dillonzq/LoveIt" target="_blank" rel="noopener noreffer" title="LoveIt 0.2.10"><i class="far fa-kiss-wink-heart fa-fw"></i> LoveIt</a>
                </div><div class="footer-line"><i class="far fa-copyright fa-fw"></i><span itemprop="copyrightYear">2021</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/" target="_blank">飞雪无情</a></span></div>
        </div>
    </footer></div>

        <div id="fixed-buttons"><a href="#" id="back-to-top" class="fixed-button" title="Back to Top">
                <i class="fas fa-arrow-up fa-fw"></i>
            </a><a href="#" id="view-comments" class="fixed-button" title="View Comments">
                <i class="fas fa-comment fa-fw"></i>
            </a>
        </div><script type="text/javascript" src="/lib/smooth-scroll/smooth-scroll.min.js"></script><script type="text/javascript" src="/lib/lazysizes/lazysizes.min.js"></script><script type="text/javascript" src="/lib/clipboard/clipboard.min.js"></script><script type="text/javascript" src="/lib/sharer/sharer.min.js"></script><script type="text/javascript">window.config={"code":{"copyTitle":"Copy to clipboard","maxShownLines":10},"comment":{}};</script><script type="text/javascript" src="/js/theme.min.js"></script></body>
</html>
